{
"cells": [
{
"cell_type": "markdown",
"id": "e86e7156",
"metadata": {},
"source": [
"# Machine Learning in MusicBox\n",
"\n",
"While MusicBox does not support machine learning directly, it is possible to feed in the model's output to a learner to create a generalized machine learning (ML) model.\n",
"Machine learning involves the development of statistical algorithms that learn from existing data so that the model can be generalized to new data.\n",
"This tutorial will go through a very basic example of running a simulation with the data being passed into a linear regression model as well as a random forest model.\n",
"Do note that both of the models that will be created are toy models and do not represent real-life situtations."
]
},
{
"cell_type": "markdown",
"id": "fe618558",
"metadata": {},
"source": [
"## 1. Importing Libraries\n",
"\n",
"Below is a list of the required libraries for this tutorial:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "5144eda9",
"metadata": {},
"outputs": [],
"source": [
"from sklearn.model_selection import train_test_split\n",
"from sklearn.metrics import root_mean_squared_error\n",
"from sklearn.linear_model import LinearRegression\n",
"from sklearn.ensemble import RandomForestRegressor\n",
"from sklearn.preprocessing import MinMaxScaler\n",
"from acom_music_box import MusicBox, Examples\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import pandas as pd"
]
},
{
"cell_type": "markdown",
"id": "ce1d8b6d",
"metadata": {},
"source": [
"## 2. Setting up and Solving the System\n",
"\n",
"This code cell is simply a copy of the setup from the [Loading Custom Box Models Tutorial](3.%20loading_custom_box_models.ipynb) but with the Chapman reaction rather than the Analytical reaction."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "b3e011c2",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
" \r"
]
},
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
time.s
\n",
"
ENV.temperature.K
\n",
"
ENV.pressure.Pa
\n",
"
ENV.air number density.mol m-3
\n",
"
CONC.Ar.mol m-3
\n",
"
CONC.CO2.mol m-3
\n",
"
CONC.H2O.mol m-3
\n",
"
CONC.N2.mol m-3
\n",
"
CONC.O.mol m-3
\n",
"
CONC.O1D.mol m-3
\n",
"
CONC.O2.mol m-3
\n",
"
CONC.O3.mol m-3
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
0.0
\n",
"
217.6
\n",
"
1394.3
\n",
"
0.770661
\n",
"
0.00771
\n",
"
0.000308
\n",
"
0.0231
\n",
"
0.601
\n",
"
3.580000e-11
\n",
"
1.830000e-17
\n",
"
0.162000
\n",
"
0.000006
\n",
"
\n",
"
\n",
"
1
\n",
"
60.0
\n",
"
217.6
\n",
"
1394.3
\n",
"
0.770661
\n",
"
0.00771
\n",
"
0.000308
\n",
"
0.0231
\n",
"
0.601
\n",
"
0.000000e+00
\n",
"
0.000000e+00
\n",
"
0.162000
\n",
"
0.000006
\n",
"
\n",
"
\n",
"
2
\n",
"
120.0
\n",
"
217.6
\n",
"
1394.3
\n",
"
0.770661
\n",
"
0.00771
\n",
"
0.000308
\n",
"
0.0231
\n",
"
0.601
\n",
"
0.000000e+00
\n",
"
0.000000e+00
\n",
"
0.162000
\n",
"
0.000006
\n",
"
\n",
"
\n",
"
3
\n",
"
180.0
\n",
"
217.6
\n",
"
1394.3
\n",
"
0.770661
\n",
"
0.00771
\n",
"
0.000308
\n",
"
0.0231
\n",
"
0.601
\n",
"
0.000000e+00
\n",
"
0.000000e+00
\n",
"
0.162000
\n",
"
0.000006
\n",
"
\n",
"
\n",
"
4
\n",
"
240.0
\n",
"
217.6
\n",
"
1394.3
\n",
"
0.770661
\n",
"
0.00771
\n",
"
0.000308
\n",
"
0.0231
\n",
"
0.601
\n",
"
0.000000e+00
\n",
"
0.000000e+00
\n",
"
0.162000
\n",
"
0.000006
\n",
"
\n",
"
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
\n",
"
\n",
"
4316
\n",
"
258960.0
\n",
"
217.6
\n",
"
1394.3
\n",
"
0.770661
\n",
"
0.00771
\n",
"
0.000308
\n",
"
0.0231
\n",
"
0.601
\n",
"
7.553605e-11
\n",
"
4.828101e-17
\n",
"
0.161998
\n",
"
0.000008
\n",
"
\n",
"
\n",
"
4317
\n",
"
259020.0
\n",
"
217.6
\n",
"
1394.3
\n",
"
0.770661
\n",
"
0.00771
\n",
"
0.000308
\n",
"
0.0231
\n",
"
0.601
\n",
"
7.553831e-11
\n",
"
4.828246e-17
\n",
"
0.161998
\n",
"
0.000008
\n",
"
\n",
"
\n",
"
4318
\n",
"
259080.0
\n",
"
217.6
\n",
"
1394.3
\n",
"
0.770661
\n",
"
0.00771
\n",
"
0.000308
\n",
"
0.0231
\n",
"
0.601
\n",
"
7.554057e-11
\n",
"
4.828391e-17
\n",
"
0.161998
\n",
"
0.000008
\n",
"
\n",
"
\n",
"
4319
\n",
"
259140.0
\n",
"
217.6
\n",
"
1394.3
\n",
"
0.770661
\n",
"
0.00771
\n",
"
0.000308
\n",
"
0.0231
\n",
"
0.601
\n",
"
7.554284e-11
\n",
"
4.828536e-17
\n",
"
0.161998
\n",
"
0.000008
\n",
"
\n",
"
\n",
"
4320
\n",
"
259200.0
\n",
"
217.6
\n",
"
1394.3
\n",
"
0.770661
\n",
"
0.00771
\n",
"
0.000308
\n",
"
0.0231
\n",
"
0.601
\n",
"
7.554510e-11
\n",
"
4.828680e-17
\n",
"
0.161998
\n",
"
0.000008
\n",
"
\n",
" \n",
"
\n",
"
4321 rows × 12 columns
\n",
"
"
],
"text/plain": [
" time.s ENV.temperature.K ENV.pressure.Pa \\\n",
"0 0.0 217.6 1394.3 \n",
"1 60.0 217.6 1394.3 \n",
"2 120.0 217.6 1394.3 \n",
"3 180.0 217.6 1394.3 \n",
"4 240.0 217.6 1394.3 \n",
"... ... ... ... \n",
"4316 258960.0 217.6 1394.3 \n",
"4317 259020.0 217.6 1394.3 \n",
"4318 259080.0 217.6 1394.3 \n",
"4319 259140.0 217.6 1394.3 \n",
"4320 259200.0 217.6 1394.3 \n",
"\n",
" ENV.air number density.mol m-3 CONC.Ar.mol m-3 CONC.CO2.mol m-3 \\\n",
"0 0.770661 0.00771 0.000308 \n",
"1 0.770661 0.00771 0.000308 \n",
"2 0.770661 0.00771 0.000308 \n",
"3 0.770661 0.00771 0.000308 \n",
"4 0.770661 0.00771 0.000308 \n",
"... ... ... ... \n",
"4316 0.770661 0.00771 0.000308 \n",
"4317 0.770661 0.00771 0.000308 \n",
"4318 0.770661 0.00771 0.000308 \n",
"4319 0.770661 0.00771 0.000308 \n",
"4320 0.770661 0.00771 0.000308 \n",
"\n",
" CONC.H2O.mol m-3 CONC.N2.mol m-3 CONC.O.mol m-3 CONC.O1D.mol m-3 \\\n",
"0 0.0231 0.601 3.580000e-11 1.830000e-17 \n",
"1 0.0231 0.601 0.000000e+00 0.000000e+00 \n",
"2 0.0231 0.601 0.000000e+00 0.000000e+00 \n",
"3 0.0231 0.601 0.000000e+00 0.000000e+00 \n",
"4 0.0231 0.601 0.000000e+00 0.000000e+00 \n",
"... ... ... ... ... \n",
"4316 0.0231 0.601 7.553605e-11 4.828101e-17 \n",
"4317 0.0231 0.601 7.553831e-11 4.828246e-17 \n",
"4318 0.0231 0.601 7.554057e-11 4.828391e-17 \n",
"4319 0.0231 0.601 7.554284e-11 4.828536e-17 \n",
"4320 0.0231 0.601 7.554510e-11 4.828680e-17 \n",
"\n",
" CONC.O2.mol m-3 CONC.O3.mol m-3 \n",
"0 0.162000 0.000006 \n",
"1 0.162000 0.000006 \n",
"2 0.162000 0.000006 \n",
"3 0.162000 0.000006 \n",
"4 0.162000 0.000006 \n",
"... ... ... \n",
"4316 0.161998 0.000008 \n",
"4317 0.161998 0.000008 \n",
"4318 0.161998 0.000008 \n",
"4319 0.161998 0.000008 \n",
"4320 0.161998 0.000008 \n",
"\n",
"[4321 rows x 12 columns]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"box_model = MusicBox()\n",
"conditions_path = Examples.Chapman.path\n",
"box_model.loadJson(conditions_path)\n",
"df = box_model.solve()\n",
"display(df)"
]
},
{
"cell_type": "markdown",
"id": "ea075da1",
"metadata": {},
"source": [
"## 3. Defining the Independent and Dependent Variables\n",
"\n",
"Next, the independent and dependent variables must be defined.\n",
"For any ML model, your independent variables will be predicting the dependent variables.\n",
"Here, the indepedent variables are two species' concentrations: O and O1D, while the dependent variable is a third species' concentration: O3\n",
"For more complicated systems where the temperature, pressure, or time step length vary throughout the simulation, those should also be added as independent variables."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "fafad7c9",
"metadata": {},
"outputs": [],
"source": [
"x = df[['CONC.O.mol m-3', 'CONC.O1D.mol m-3']]\n",
"y = df[['CONC.O3.mol m-3']]"
]
},
{
"cell_type": "markdown",
"id": "8bea9cf2",
"metadata": {},
"source": [
"## 4. Making the Train-Test Split for the Data\n",
"\n",
"Once the independent and dependent variables are defined, they can each be split into training and testing data.\n",
"Training data refers to the data that is fed into the model in order to fit it.\n",
"For linear regression, this fit will be an equation of the form ax + b, where a represents the slope and b represents the y-intercept.\n",
"On the other hand, the testing data is data that the model is blind to and will attempt to predict after being shown the training data.\n",
"For this model, 70% of the data will be for training, and 30% will be for testing.\n",
"Also, shuffling is disabled so that the every testing data point comes after every training data point in time.\n",
"This directs the model to try and predict the future (test data) from past data points (train data).\n",
"You can see this by looking at the indices in the displayed training and testing data."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "9054c1fd",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
"
],
"text/plain": [
" CONC.O3.mol m-3\n",
"3024 0.000007\n",
"3025 0.000007\n",
"3026 0.000007\n",
"3027 0.000007\n",
"3028 0.000007\n",
"... ...\n",
"4316 0.000008\n",
"4317 0.000008\n",
"4318 0.000008\n",
"4319 0.000008\n",
"4320 0.000008\n",
"\n",
"[1297 rows x 1 columns]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Split data into train/test (70/30)\n",
"x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, shuffle=False)\n",
"\n",
"display(x_train)\n",
"display(y_train)\n",
"display(x_test)\n",
"display(y_test)"
]
},
{
"cell_type": "markdown",
"id": "cc008163",
"metadata": {},
"source": [
"## 5. Normalizing the Concentrations\n",
"\n",
"For many ML models, including linear regression, normalizing your data will ensure that each of the input and output features are weighted equally when they are not on the same scale initially.\n",
"To normalize the data, two [MinMaxScaler()](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MinMaxScaler.html) objects are created, one for the dependent concentration variables, and one for the independent concentration variables.\n",
"These scalers can be fitted and alter the training data concentration columns in place with its fit_transform() function by taking in a column that is used to calcuate the normalized values.\n",
"However, the testing data is scaled with the transform() function since you never want to fit on your testing data, as it will lead to data leakages, causing the model to overfit.\n",
"All the unscaled and scaled DataFrames are then displayed so that you can see what the normalization does to the concentration values."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "4f9ea151",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
"
],
"text/plain": [
" CONC.O3.mol m-3\n",
"4316 1.505976\n",
"4317 1.506288\n",
"4318 1.506601\n",
"4319 1.506914\n",
"4320 1.507226"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"y_scaler = MinMaxScaler()\n",
"y_train_scaled = y_scaler.fit_transform(y_train)\n",
"y_train_scaled_df = pd.DataFrame(y_train_scaled, columns=y_train.columns, index=y_train.index)\n",
"display(y_train.tail())\n",
"display(y_train_scaled_df.tail())\n",
"\n",
"y_test_scaled = y_scaler.transform(y_test)\n",
"y_test_scaled_df = pd.DataFrame(y_test_scaled, columns=y_test.columns, index=y_test.index)\n",
"display(y_test.tail())\n",
"display(y_test_scaled_df.tail())"
]
},
{
"cell_type": "markdown",
"id": "e2e0d4c0",
"metadata": {},
"source": [
"## 6. Fitting, Predicting, and Evaluating the Model\n",
"\n",
"Since all of the model preparation is out of the way, the model can now be created, fitted with the training data, and used to predict from the testing data.\n",
"However, y_pred is currently normalized since it was fitted and predicted on normalized data, and it needs to be un-normalized so that it can be evaluated and visualized with the correct scale.\n",
"To un-normalize the prediction array, simply take the y_scaler variable from step 5 and call its inverse_transform() function to undo the normalization.\n",
"With the predicted concentration values calculated, the root mean square error (RMSE) can be calculated as well.\n",
"RMSE represents the average magnitude that a prediction is off.\n",
"For example, a RMSE of 1 means the average concentration prediction is 1 mol/m3 off from being correct."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "1515039e",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Test RMSE: 5.239710325081405e-07\n"
]
}
],
"source": [
"# Fit on training set\n",
"model = LinearRegression()\n",
"model.fit(x_train_scaled, y_train_scaled)\n",
"\n",
"y_pred = model.predict(x_test_scaled)\n",
"y_pred = y_scaler.inverse_transform(y_pred)\n",
"test_rmse = root_mean_squared_error(y_test, y_pred)\n",
"print(f\"Test RMSE: {test_rmse}\")"
]
},
{
"cell_type": "markdown",
"id": "941e30b5",
"metadata": {},
"source": [
"## 7. Preparing the Predicted Data for Visualization\n",
"\n",
"In its current state, the y_pred array cannot be visualized properly due to indexing issues; it only represents 30% of the original dataset, so 70% of the indices are missing.\n",
"To fix the missing indices issue, the y_pred array is bundled into a DataFrame, taking the test indices as input initally.\n",
"Then, the DataFrame is reindexed based on the original DataFrame's indices. This will add back the missing indices with all NaN values, indicating that those time steps should not be plotted.\n",
"The DataFrame is displayed before and after the reindexing so you can get an idea of what the reindex() function is doing."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "49f785b6",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
"
],
"text/plain": [
" Predicted CONC.O3.mol m-3\n",
"0 NaN\n",
"1 NaN\n",
"2 NaN\n",
"3 NaN\n",
"4 NaN\n",
"... ...\n",
"4316 0.000007\n",
"4317 0.000007\n",
"4318 0.000007\n",
"4319 0.000007\n",
"4320 0.000007\n",
"\n",
"[4321 rows x 1 columns]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"conc_pred = pd.DataFrame(y_pred, index=y_test.index, columns=['Predicted CONC.O3.mol m-3'])\n",
"display(conc_pred)\n",
"\n",
"conc_pred = conc_pred.reindex(df.index)\n",
"display(conc_pred)"
]
},
{
"cell_type": "markdown",
"id": "3d9a7d13",
"metadata": {},
"source": [
"## 8. Plot the Linear Regression Model\n",
"\n",
"This code cell simply plots the dependent species' (O3) concentration over time, with the predicted concentration only covering the time steps present in the testing data.\n",
"Due to the lack of helpful independent variables in this model, it is incredibly inaccurate, but ML models will have a lower RMSE when done well."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "1ea04f8b",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
"
"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plt.plot(df['time.s'], conc_pred['Predicted CONC.O3.mol m-3'], label='Predicted CONC.O3.mol m-3')\n",
"plt.plot(df['time.s'], df['CONC.O3.mol m-3'], label='CONC.O3.mol m-3')\n",
"plt.title('Concentration over time')\n",
"plt.ylabel('Concentration (mol m-3)')\n",
"plt.xlabel('Time (s)')\n",
"plt.legend(loc='upper center', fontsize=6)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "98d58cb2",
"metadata": {},
"source": [
"## 9. Running and Evaluating the Random Forest Model\n",
"\n",
"With the training and testing data already set up, there is not much work to get the random forest model running.\n",
"However, one new thing here is the addition of the n_estimators argument which defines the number of trees in the model. Feel free to change this number to experiment.\n",
"There is also an additional step in the fit() function, which is wrapping the y training data into NumPy's ravel() function due to a quirk with the RandomForestRegressor class.\n",
"As with the linear regression model, it is fitted based on the training data, ran on the testing data, and then evaluated against the ground truth.\n",
"Due to the use of the ravel() function, an additional line needs to be added at the top to fix the y_pred array's incorrect shape.\n",
"To achieve this, the reshape() function is called with the -1 parameter representing any number of rows and the 1 parameter representing 1 column.\n",
"Thus, this makes the y_pred array a single column with a row for every predicted time step.\n",
"Do note how the random forest model is a bit more accurate than the linear model (~4.93e-7 RMSE vs ~5.24e-7 RMSE).\n",
"This is expected behavior for the models, as linear regression should be less accurate than random forest when the data itself is not linear."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "856c9729",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Test RMSE: 4.928728531233833e-07\n"
]
}
],
"source": [
"# Fit on training set\n",
"model = RandomForestRegressor(n_estimators=100)\n",
"model.fit(x_train_scaled_df, np.ravel(y_train_scaled_df))\n",
"\n",
"y_pred = model.predict(x_test_scaled_df)\n",
"y_pred = y_pred.reshape(-1, 1)\n",
"y_pred = y_scaler.inverse_transform(y_pred)\n",
"test_rmse = root_mean_squared_error(y_test, y_pred)\n",
"print(f\"Test RMSE: {test_rmse}\")"
]
},
{
"cell_type": "markdown",
"id": "2a55f9ad",
"metadata": {},
"source": [
"## 10. Data Preparation for Visualization\n",
"\n",
"This step is identical and achieves the same goal as step 7, refer to that step for an explanation."
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "58ecd9b2",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"